package com.i1314i.reportsystem.config;

import com.i1314i.reportsystem.filter.TokenFilter;
import com.i1314i.reportsystem.shiro.credentials.RetryLimitHashedCredentialsMatcher;
import com.i1314i.reportsystem.shiro.realm.AdminLoginRealm;
import com.i1314i.reportsystem.shiro.realm.CustomRealm;
import com.i1314i.reportsystem.shiro.realm.UserLoginRealm;
import com.i1314i.reportsystem.shiro.realmAuthenticator.MyModularRealmAuthenticator;
import org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy;
import org.apache.shiro.authc.pam.FirstSuccessfulStrategy;
import org.apache.shiro.authc.pam.ModularRealmAuthenticator;
import org.apache.shiro.authz.ModularRealmAuthorizer;
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.Filter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * shiro配置类
 * @author 平行时空
 * @created 2018-09-17 17:04
 **/

@Configuration
public class ShiroConfig {
    @Bean
    public ShiroFilterFactoryBean factory(SecurityManager securityManager) {
        ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
        // 添加自己的过滤器
        Map<String, Filter> filterMap = new HashMap<>();
        //设置我们自定义的token过滤器
        filterMap.put("token", new TokenFilter());
        factoryBean.setFilters(filterMap);
        factoryBean.setSecurityManager(securityManager);
        Map<String, String> filterRuleMap = new HashMap<>();
        // 所有请求通过我们自己的token Filter
        filterRuleMap.put("/**", "token");
        // 访问 /unauthorized/** 不通过TokenFilters
        filterRuleMap.put("/unauthorized/**", "anon");
        filterRuleMap.put("/public/**", "anon");
        factoryBean.setFilterChainDefinitionMap(filterRuleMap);
        return factoryBean;
    }


    /**
     * 注入 securityManager
     */
    @Bean
    public DefaultWebSecurityManager securityManager(CustomRealm customRealm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        // 设置自定义 realm.

        securityManager.setAuthenticator(modularRealmAuthenticator());
        /*
         * 关闭shiro自带的session，详情见文档
         * http://shiro.apache.org/session-management.html#SessionManagement-StatelessApplications%28Sessionless%29
         */
        DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
        DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
        defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
        subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
        securityManager.setSubjectDAO(subjectDAO);
        return securityManager;
    }

    @Bean
    public ModularRealmAuthenticator modularRealmAuthenticator(){
        ModularRealmAuthenticator realmAuthenticator=new MyModularRealmAuthenticator();
        List<Realm>realmList=new ArrayList<>();
        realmList.add(userLoginRealm());  //普通用户
        realmList.add(customRealm());  //token
        realmList.add(adminLoginRealm());  //管理员
        realmAuthenticator.setRealms(realmList);
        realmAuthenticator.setAuthenticationStrategy(firstSuccessfulStrategy());
        return realmAuthenticator;
    }



    /**
     * 添加注解支持
     */
    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        // 强制使用cglib，防止重复代理和可能引起代理出错的问题
        // https://zhuanlan.zhihu.com/p/29161098
        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
        return defaultAdvisorAutoProxyCreator;
    }

    /**
     * 用户登录realm
     * @return
     */
    @Bean
    public UserLoginRealm userLoginRealm(){
        UserLoginRealm loginRealm= new UserLoginRealm();
        loginRealm.setCredentialsMatcher(retryLimitHashedCredentialsMatcher());
        return loginRealm;
    }


    @Bean
    public AdminLoginRealm adminLoginRealm(){
        AdminLoginRealm loginRealm=new AdminLoginRealm();
        loginRealm.setCredentialsMatcher(retryLimitHashedCredentialsMatcher());
        return loginRealm;
    }

    @Bean
    public CustomRealm customRealm(){
        return new CustomRealm();
    }

    /**
     * 验证错误密码次数锁定
     * @return
     */
    @Bean
    public RetryLimitHashedCredentialsMatcher retryLimitHashedCredentialsMatcher(){
        RetryLimitHashedCredentialsMatcher matcher=new RetryLimitHashedCredentialsMatcher();
        matcher.setHashAlgorithmName("md5");
        matcher.setHashIterations(2);
        matcher.setStoredCredentialsHexEncoded(true);
        return matcher;
    }


    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(securityManager);
        return advisor;
    }

    @Bean
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    /**
     * 只要有一个Realm验证成功即可，和FirstSuccessfulStrategy不同，返回所有Realm身份验证成功的认证信息；
     * @return
     */
    public AtLeastOneSuccessfulStrategy atLeastOneSuccessfulStrategy(){
        return new AtLeastOneSuccessfulStrategy();
    }

    /**
     * 只要有一个Realm验证成功即可，只返回第一个Realm身份验证成功的认证信息，其他的忽略
     * @return
     */
    public FirstSuccessfulStrategy firstSuccessfulStrategy(){
        return new FirstSuccessfulStrategy();
    }



}
